Skip to content

Method: letsWinIfPossible(VGFieldState, VGAnswerEnum, Boolean)

1: package de.fhdw.gaming.ipspiel22.vierGewinnt.strategy;
2:
3: import java.util.ArrayList;
4: import java.util.Collections;
5: import java.util.List;
6: import java.util.Objects;
7:
8: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.VGMove;
9: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.AbstractVGMove;
10: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG1ColumnMove;
11: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG2ColumnMove;
12: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG3ColumnMove;
13: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG4ColumnMove;
14: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG5ColumnMove;
15: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG6ColumnMove;
16: import de.fhdw.gaming.ipspiel22.vierGewinnt.moves.impl.VG7ColumnMove;
17: import de.fhdw.gaming.core.domain.GameException;
18: import de.fhdw.gaming.ipspiel22.searchtree.domain.MinMaxGame;
19: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGAnswerEnum;
20: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGBoard;
21: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGField;
22: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGFieldState;
23: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGPlayer;
24: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGPosition;
25: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.VGState;
26: import de.fhdw.gaming.ipspiel22.vierGewinnt.domain.impl.VGBoardImpl;
27:
28: /**
29: * MinMaxViergewinnt.
30: */
31: @SuppressWarnings("PMD")
32: public class MinMaxViergewinnt implements MinMaxGame<VGPlayer, VGState, VGMove> {
33: /**
34: * Current given state.
35: */
36: private final VGState vgState;
37:
38: /**
39: * Current given state.
40: */
41: private final VGBoard inistialBoard;
42:
43: /**
44: * Current given player.
45: */
46: private final VGPlayer player;
47:
48: /**
49: * Playercolour for algorithm.
50: */
51: private Boolean playercolour;
52:
53: /**
54: * Saved Move.
55: */
56: private VGMove savedMove;
57:
58: /**
59: * For creating MinMaxViergewinnt.
60: *
61: * @param state Current given state.
62: * @param player Current given player.
63: */
64: public MinMaxViergewinnt(final VGState state, final VGPlayer player) {
65: this.vgState = state;
66: this.player = player;
67: this.playercolour = player.isUsingRedChips();
68: this.inistialBoard = new VGBoardImpl((VGBoardImpl) state.getBoard());
69: }
70:
71: @Override
72: public double evaluateStateful() {
73: double stateful;
74:
75: final VGFieldState state = playercolour ? VGFieldState.RED : VGFieldState.YELLOW;
76: final VGFieldState otherPlayerState = !playercolour ? VGFieldState.RED : VGFieldState.YELLOW;
77:
78: final List<Double> checkedStates = new ArrayList<>();
79: if (this.playercolour == this.player.isUsingRedChips()) {
80:
81: checkedStates.addAll(twoCombo(vgState.getBoard(), state, 6.0));
82: checkedStates.addAll(threeCombo(vgState.getBoard(), state, 12.0));
83: checkedStates.addAll(fourCombo(vgState.getBoard(), state, 24.0));
84:
85: stateful = Collections.max(checkedStates);
86: stateful += checkMiddle(vgState.getBoard(), playercolour);
87:
88: final List<Double> firstPossibleMoves = new ArrayList<>();
89: firstPossibleMoves.add(ifThreeWithMove(otherPlayerState,
90: !this.player.isUsingRedChips()));
91: firstPossibleMoves.add(ifThreeWithMove(state, this.player.isUsingRedChips()));
92: firstPossibleMoves.add(ifWonWithMove(otherPlayerState,
93: !this.player.isUsingRedChips()));
94: firstPossibleMoves.add(ifWonWithMove(state, this.player.isUsingRedChips()));
95: stateful += Collections.max(firstPossibleMoves);
96:
97: } else {
98: checkedStates.addAll(threeCombo(vgState.getBoard(), state, 5.0));
99: checkedStates.addAll(fourCombo(vgState.getBoard(), state, 20.0));
100:
101: stateful = Collections.max(checkedStates);
102: }
103: return stateful;
104: }
105:
106: @Override
107: public boolean isGameOver() {
108: final List<VGField> allFields = new ArrayList<>();
109: vgState.getBoard().getFields().forEach(allFields::addAll);
110:
111: if (allFields.stream().noneMatch(vgField -> vgField.getState().equals(VGFieldState.EMPTY))) {
112: return true;
113: } else {
114: return checkWinner(vgState.getBoard(), playercolour); // checkWinner(!playercolour);
115: }
116: }
117:
118: @Override
119: public List<VGMove> getPossibleMoves() {
120: final List<VGMove> movesList = new ArrayList<>();
121:
122: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.FIRSTCOLUMN))) {
123: movesList.add(new VG1ColumnMove());
124: }
125: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.SECONDCOLUMN))) {
126: movesList.add(new VG2ColumnMove());
127: }
128: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.THIRDCOLUMN))) {
129: movesList.add(new VG3ColumnMove());
130: }
131: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.FOURTHCOLUMN))) {
132: movesList.add(new VG4ColumnMove());
133: }
134: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.FITFHCOLUMN))) {
135: movesList.add(new VG5ColumnMove());
136: }
137: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.SIXTHCOLUMN))) {
138: movesList.add(new VG6ColumnMove());
139: }
140: if (Objects.nonNull(vgState.getBoard().getNextFieldInColumn(VGAnswerEnum.SEVENTHCOLUMN))) {
141: movesList.add(new VG7ColumnMove());
142: }
143: Collections.shuffle(movesList);
144: return movesList;
145: }
146:
147: @Override
148: public void commitMove(final VGMove move) throws GameException {
149: final VGPlayer playerMove = this.playercolour ? vgState.getRedPlayer() : vgState.getYellowPlayer();
150:
151: move.applyTo(this.vgState, playerMove);
152: this.playercolour = !this.playercolour;
153:
154: }
155:
156: @Override
157: public void rollbackMove(final VGMove move) {
158: if (move instanceof AbstractVGMove) {
159: vgState.getBoard().getFields().get(((AbstractVGMove) move).getColumnInt() - 1);
160:
161: int count = 0;
162: VGField field = vgState.getBoard().getFields().get(((AbstractVGMove) move)
163: .getColumnInt() - 1).get(count);
164: while (!field.getState().equals(VGFieldState.EMPTY) && count < 5) {
165: count += 1;
166: field = vgState.getBoard().getFields().get(((AbstractVGMove) move)
167: .getColumnInt() - 1).get(count);
168: }
169: vgState.getBoard().getFields().get(((AbstractVGMove) move).getColumnInt() - 1)
170: .get(count == 0 ? count : count - 1)
171: .setState(VGFieldState.EMPTY);
172: }
173: this.playercolour = !this.playercolour;
174: }
175:
176: @Override
177: public VGMove saveFirstMoves(final VGMove move) {
178: this.savedMove = move;
179: return move;
180: }
181:
182: /**
183: * If possible to win with next move.
184: *
185: * @param state
186: * @param playercolor
187: * @return
188: */
189: private double ifWonWithMove(final VGFieldState state, final Boolean playercolor) {
190: final double value = playercolor == player.isUsingRedChips() ? 100.0 : 50.0;
191: return letsWinIfPossible(state, getMoveAsAnswer(this.savedMove),
192: playercolor) ? value : 0;
193: }
194:
195: /**
196: * converts Move to Answer.
197: *
198: * @param move
199: * @return
200: */
201: private VGAnswerEnum getMoveAsAnswer(final VGMove move) {
202: if (move instanceof VG1ColumnMove) {
203: return VGAnswerEnum.FIRSTCOLUMN;
204: } else if (move instanceof VG2ColumnMove) {
205: return VGAnswerEnum.SECONDCOLUMN;
206: } else if (move instanceof VG3ColumnMove) {
207: return VGAnswerEnum.THIRDCOLUMN;
208: } else if (move instanceof VG4ColumnMove) {
209: return VGAnswerEnum.FOURTHCOLUMN;
210: } else if (move instanceof VG5ColumnMove) {
211: return VGAnswerEnum.FITFHCOLUMN;
212: } else if (move instanceof VG6ColumnMove) {
213: return VGAnswerEnum.SIXTHCOLUMN;
214: } else {
215: return VGAnswerEnum.SEVENTHCOLUMN;
216: }
217: }
218:
219: /**
220: * If possible to have three chips in next move.
221: *
222: * @param state
223: * @param playercolor
224: * @return
225: */
226: private double ifThreeWithMove(final VGFieldState state, final boolean playercolor) {
227: final double value = playercolor == player.isUsingRedChips() ? 20.0 : 10.0;
228: return putThreeIfPossible(state, getMoveAsAnswer(this.savedMove)) ? value : 0;
229: }
230:
231: /**
232: * Win if possible.
233: *
234: * @param state
235: * @param column
236: * @param playercolor
237: * @return
238: */
239: private Boolean letsWinIfPossible(final VGFieldState state, final VGAnswerEnum column,
240: final Boolean playercolor) {
241: final VGField field = inistialBoard.getNextFieldInColumn(column);
242:• Boolean won = false;
243: if (Objects.nonNull(field)) {
244: field.setState(state);
245: won = checkWinner(inistialBoard, playercolor);
246: field.setState(VGFieldState.EMPTY);
247: }
248: return won;
249: }
250:
251: /**
252: * Three if possible.
253: *
254: * @param state
255: * @param column
256: * @return
257: */
258: private Boolean putThreeIfPossible(final VGFieldState state, final VGAnswerEnum column) {
259: final VGField field = inistialBoard.getNextFieldInColumn(column);
260: Boolean won = false;
261: if (Objects.nonNull(field)) {
262: field.setState(state);
263: won = Collections.max(threeCombo(inistialBoard, state, 20.0)) > 0;
264: field.setState(VGFieldState.EMPTY);
265: }
266: return won;
267: }
268:
269: // -----------------------------------------------------------------------------------------------------
270:
271: /**
272: * Returns boolean, if Player has won.
273: *
274: * @param board
275: * @param usingRedChips The current player.
276: */
277: private boolean checkWinner(final VGBoard board, final Boolean usingRedChips) {
278: final VGFieldState state = usingRedChips ? VGFieldState.RED : VGFieldState.YELLOW;
279: return checkHorizontaleLeftToRight(board, state, state, state, state)
280: || checkVertikaleDownUp(board, state, state, state, state)
281: || checkDiagonaleDownLeftUpRight(board, state, state, state, state)
282: || checkDiagonaleDownRightUpLeftght(board, state, state, state, state);
283: }
284:
285: /**
286: * Checks condition, if true return rating else 0.0.
287: * @param condition
288: * @param rating
289: * @return
290: */
291: private Double checkCondition(final Boolean condition, final Double rating) {
292: return condition ? rating : 0.0;
293: }
294:
295: /**
296: * Checks if a two combo exists.
297: *
298: * @param board
299: * @param state
300: * @param rating
301: * @return
302: */
303: public List<Double> twoCombo(final VGBoard board, final VGFieldState state,
304: final Double rating) {
305: final List<Double> checkedStates = new ArrayList<>();
306: checkedStates
307: .add(checkCondition(checkDiagonaleDownLeftUpRight(board, VGFieldState.EMPTY, state,
308: VGFieldState.EMPTY, state), rating));
309: checkedStates.add(
310: checkCondition(checkDiagonaleDownRightUpLeftght(board, VGFieldState.EMPTY, state,
311: VGFieldState.EMPTY, state), rating));
312: checkedStates
313: .add(checkCondition(checkHorizontaleLeftToRight(board, VGFieldState.EMPTY, state,
314: VGFieldState.EMPTY, state), rating));
315:
316: checkedStates
317: .add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, VGFieldState.EMPTY,
318: state, VGFieldState.EMPTY), rating));
319: checkedStates.add(
320: checkCondition(checkDiagonaleDownRightUpLeftght(board, state, VGFieldState.EMPTY,
321: state, VGFieldState.EMPTY), rating));
322: checkedStates
323: .add(checkCondition(checkHorizontaleLeftToRight(board, state, VGFieldState.EMPTY,
324: state, VGFieldState.EMPTY), rating));
325:
326: checkedStates
327: .add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, state, VGFieldState.EMPTY,
328: VGFieldState.EMPTY), rating));
329: checkedStates.add(
330: checkCondition(checkDiagonaleDownRightUpLeftght(board, state, state, VGFieldState.EMPTY,
331: VGFieldState.EMPTY), rating));
332: checkedStates
333: .add(checkCondition(checkHorizontaleLeftToRight(board, state, state, VGFieldState.EMPTY,
334: VGFieldState.EMPTY), rating));
335:
336: checkedStates
337: .add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, VGFieldState.EMPTY,
338: VGFieldState.EMPTY, state), rating));
339: checkedStates.add(
340: checkCondition(checkDiagonaleDownRightUpLeftght(board, state, VGFieldState.EMPTY,
341: VGFieldState.EMPTY, state), rating));
342: checkedStates
343: .add(checkCondition(checkHorizontaleLeftToRight(board, state, VGFieldState.EMPTY,
344: VGFieldState.EMPTY, state), rating));
345:
346: checkedStates
347: .add(checkCondition(checkDiagonaleDownLeftUpRight(board, VGFieldState.EMPTY,
348: VGFieldState.EMPTY, state, state), rating));
349: checkedStates.add(
350: checkCondition(checkDiagonaleDownRightUpLeftght(board, VGFieldState.EMPTY,
351: VGFieldState.EMPTY, state, state), rating));
352: checkedStates
353: .add(checkCondition(checkHorizontaleLeftToRight(board, VGFieldState.EMPTY,
354: VGFieldState.EMPTY, state, state), rating));
355:
356: checkedStates
357: .add(checkCondition(checkVertikaleDownUp(board, state, state, VGFieldState.EMPTY,
358: VGFieldState.EMPTY), rating));
359: return checkedStates;
360: }
361:
362: /**
363: * Checks if three Combo exists.
364: *
365: * @param board
366: * @param state
367: * @param rating
368: * @return
369: */
370: public List<Double> threeCombo(final VGBoard board, final VGFieldState state, final Double rating) {
371: // Drei gewinnt
372: final List<Double> checkedStates = new ArrayList<>();
373: checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, state, state,
374: VGFieldState.EMPTY, state), rating));
375: checkedStates
376: .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, state, state,
377: VGFieldState.EMPTY, state), rating));
378: checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, state, state,
379: VGFieldState.EMPTY, state), rating));
380:
381: checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, state,
382: VGFieldState.EMPTY, state, state), rating));
383: checkedStates
384: .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, state,
385: VGFieldState.EMPTY, state, state), rating));
386: checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, state,
387: VGFieldState.EMPTY, state, state), rating));
388:
389: checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board,
390: VGFieldState.EMPTY, state, state, state), rating));
391: checkedStates
392: .add(checkCondition(checkDiagonaleDownRightUpLeftght(board,
393: VGFieldState.EMPTY, state, state, state), rating));
394: checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board,
395: VGFieldState.EMPTY, state, state, state), rating));
396:
397: checkedStates.add(checkCondition(checkDiagonaleDownLeftUpRight(board, state,
398: state, state, VGFieldState.EMPTY), rating));
399: checkedStates.add(checkCondition(checkVertikaleDownUp(board, state, state,
400: state, VGFieldState.EMPTY), rating));
401: checkedStates
402: .add(checkCondition(checkDiagonaleDownRightUpLeftght(board, state,
403: state, state, VGFieldState.EMPTY), rating));
404: checkedStates.add(checkCondition(checkHorizontaleLeftToRight(board, state,
405: state, state, VGFieldState.EMPTY), rating));
406: return checkedStates;
407: }
408:
409: /**
410: * If four combo exists.
411: *
412: * @param board
413: * @param state
414: * @param rating
415: * @return
416: */
417: public List<Double> fourCombo(final VGBoard board, final VGFieldState state, final Double rating) {
418: // Vier gewinnt
419: final List<Double> checkedStates = new ArrayList<>();
420: checkedStates.add(checkDiagonaleDownLeftUpRight(board, state, state, state, state) ? rating : 0.0);
421: checkedStates.add(checkVertikaleDownUp(board, state, state, state, state) ? rating : 0.0);
422: checkedStates.add(checkDiagonaleDownRightUpLeftght(board, state, state, state, state) ? rating : 0.0);
423: checkedStates.add(checkHorizontaleLeftToRight(board, state, state, state, state) ? rating : 0.0);
424: return checkedStates;
425: }
426:
427:
428: /**
429: * Extra Points for chips in the middle.
430: *
431: * @param board
432: * @param usingRedChips
433: * @return result
434: */
435: private double checkMiddle(final VGBoard board, final boolean usingRedChips) {
436: double result = 0.0;
437: final VGFieldState state = usingRedChips ? VGFieldState.RED : VGFieldState.YELLOW;
438:
439: result += board.getFields().get(2).stream().filter(field -> field.getState().equals(state))
440: .mapToDouble(field -> {
441: return 2.0;
442: }).sum(); // Dritte Spalte
443: result += board.getFields().get(3).stream().filter(field -> field.getState().equals(state))
444: .mapToDouble(field -> {
445: return 5.0;
446: }).sum(); // Vierte Spalte
447: result += board.getFields().get(4).stream().filter(field -> field.getState().equals(state))
448: .mapToDouble(field -> {
449: return 2.0;
450: }).sum(); // Fünfte Spa 0;
451:
452: return result;
453: }
454:
455: /**
456: * Checks horizontal.
457: *
458: * @param board
459: * @param chip1
460: * @param chip2
461: * @param chip3
462: * @param chip4
463: * @return
464: */
465: private Boolean checkHorizontaleLeftToRight(final VGBoard board, final VGFieldState chip1,
466: final VGFieldState chip2,
467: final VGFieldState chip3, final VGFieldState chip4) {
468: for (int i = 0; i < board.getRows(); i++) {
469: for (int j = 0; j < 4; j++) {
470: if (board.getFieldAt(VGPosition.of(j, i)).getState().equals(chip1)
471: && board.getFieldAt(VGPosition.of(j + 1, i)).getState().equals(chip2)
472: && board.getFieldAt(VGPosition.of(j + 2, i)).getState().equals(chip3)
473: && board.getFieldAt(VGPosition.of(j + 3, i)).getState().equals(chip4)) {
474: return true;
475: }
476: }
477: }
478: return false;
479: }
480:
481: /**
482: * checks vertical.
483: *
484: * @param board
485: * @param chip1
486: * @param chip2
487: * @param chip3
488: * @param chip4
489: * @return
490: */
491: private Boolean checkVertikaleDownUp(final VGBoard board, final VGFieldState chip1, final VGFieldState chip2,
492: final VGFieldState chip3,
493: final VGFieldState chip4) {
494: for (int i = 0; i < board.getColumns(); i++) {
495: for (int j = 0; j < 3; j++) {
496: if (board.getFieldAt(VGPosition.of(i, j)).getState().equals(chip1)
497: && board.getFieldAt(VGPosition.of(i, j + 1)).getState().equals(chip2)
498: && board.getFieldAt(VGPosition.of(i, j + 2)).getState().equals(chip3)
499: && board.getFieldAt(VGPosition.of(i, j + 3)).getState().equals(chip4)) {
500: return true;
501: }
502: }
503: }
504: return false;
505: }
506:
507: /**
508: * checks diagonale down left to up right.
509: *
510: * @param board
511: * @param chip1
512: * @param chip2
513: * @param chip3
514: * @param chip4
515: * @return
516: */
517: private Boolean checkDiagonaleDownLeftUpRight(final VGBoard board, final VGFieldState chip1,
518: final VGFieldState chip2,
519: final VGFieldState chip3, final VGFieldState chip4) {
520: for (int i = 0; i < 3; i++) {
521: for (int j = 0; j < 4; j++) {
522: if (board.getFieldAt(VGPosition.of(j, i)).getState().equals(chip1)
523: && board.getFieldAt(VGPosition.of(j + 1, i + 1)).getState()
524: .equals(chip2)
525: && board.getFieldAt(VGPosition.of(j + 2, i + 2)).getState()
526: .equals(chip3)
527: && board.getFieldAt(VGPosition.of(j + 3, i + 3)).getState()
528: .equals(chip4)) {
529: return true;
530: }
531: }
532: }
533: return false;
534:
535: }
536:
537: /**
538: * checks diagonle down right to up left.
539: *
540: * @param board
541: * @param chip1
542: * @param chip2
543: * @param chip3
544: * @param chip4
545: * @return
546: */
547: private Boolean checkDiagonaleDownRightUpLeftght(final VGBoard board, final VGFieldState chip1,
548: final VGFieldState chip2, final VGFieldState chip3, final VGFieldState chip4) {
549: for (int i = 0; i < 3; i++) {
550: for (int j = 3; j < 7; j++) {
551: if (board.getFieldAt(VGPosition.of(j, i)).getState().equals(chip1)
552: && board.getFieldAt(VGPosition.of(j - 1, i + 1)).getState()
553: .equals(chip2)
554: && board.getFieldAt(VGPosition.of(j - 2, i + 2)).getState()
555: .equals(chip3)
556: && board.getFieldAt(VGPosition.of(j - 3, i + 3)).getState()
557: .equals(chip4)) {
558: return true;
559: }
560: }
561: }
562:
563: return false;
564: }
565:
566: }